#include "app_device.h"
#include "fcntl.h"
#include "stdio.h"
#include "unistd.h"
#include "app_pool.h"
#include "app_message.h"
#include "app_mqtt.h"
#include "app_common.h"
#include <stdlib.h>
#include <string.h>
#include "log/log.h"

static device_t *device;
/**
 * 初始化设备结构体
 */
device_t *app_device_init(char *dev_filename)
{
    // 1 初始化设备结构体 开辟空间
    device = (device_t *)malloc(sizeof(device_t));
    if (device == NULL)
    {
        log_error("malloc device error\n");
    }
    // 2 设置默认值
    device->dev_filename = dev_filename;
    int fd = open(dev_filename, O_RDWR);
    device->fd = fd;
    device->up_buffer = app_buffer_init(1024);
    device->down_buffer = app_buffer_init(1024);
    device->is_running = 1;
    device->last_write_ts_ms = 0;
    device->interval_ms = 200;
    device->post_read = NULL;
    device->pre_write = NULL;

    return device;
}

/**
 * 启动设备运行 ，开始读取芯片数据的线程 ，执行（从芯片中读取数据到上行缓冲区）
 * 1 创建一个单独线程用于读取芯片数据
 * 2 设置设备运行标志位
 */
int app_device_start()
{
    // 1 运行设备
    int ret = pthread_create(&device->read_thread, NULL, app_device_read, NULL);
    if (ret != 0)
    {
        log_error("创建设备启动线程失败..");
    }
    log_warn("设备读取线程已经启动..");

    // 2 向app_mqtt模块 注册 接收消息的回调函数
    log_info("设备模块初始化:向app_mqtt模块 注册 接收消息的回调函数 ");
    app_mqtt_registerRecvCallback(app_device_recv_from_mqtt);

    log_info("设备已经启动....");

    return 0;
}

/**
 *  ------读线程的线程函数-------
 * 从芯片中读取数据到上行缓冲区 （异步）
 * 1 从设备 文件中读取数据
 * 2 对数据进行读后预处理 把e设备格式转换为字节数组
 * 3 把字节数组写入上行缓冲区
 * 4 把数据发送到mqtt的方法和参数提交给线程池
 *
 */
void *app_device_read(void *arg)
{
    char read_buff[100] = {0};
    //* 1 从设备 文件中读取数据
    while (device->is_running)
    { // 阻塞状态读取，有数据直接返回，没有数据阻塞等待

        ssize_t real_read_size = read(device->fd, read_buff, 100);
        // sleep(2);
        // log_info("read_buff:%d", real_read_size);
        //* 2 对数据进行[读后预处理] 把e设备格式转换为字节数组
        // 此时并未对读后进行处理，即直接输出本身数据

        if (real_read_size > 0 && device->post_read)
        {
            real_read_size = device->post_read(read_buff, real_read_size);
        }
        //* 3 把字节数组转写入上行缓冲区
        if (real_read_size > 0)
        {
            // log_info("转换为json格式数据写入到缓冲区:");
            log_info("直接将字节数组格式数据写入到缓冲区,通过mqtt发送之前转为json格式");
            // app_message_charsToJson(read_buff, real_read_size);
            app_buffer_write(device->up_buffer, read_buff, real_read_size);

            //* 4 把数据发送到mqtt的方法和参数提交给线程池
            app_pool_registerTask(app_device_send_to_mqtt, device);
        }
    }
    return NULL;
}

/**
 * 从上行缓冲区中读取数据到消息队列 (交给线程池执行 异步方法)
 * 1 读取缓冲区的数据
 * 2 把字节数组格式n转为 json格式
 * 3 把json格式数据发送到mqtt
 */
int app_device_send_to_mqtt(void *arg)
{
    char read_buff[100];
    // * 1 读取缓冲区的数据
    // 读取数据
    int real_read_size = app_buffer_read(device->up_buffer, read_buff, 100);

    //* 2 把字节数组格式转为 json格式
    char *json = app_message_charsToJson(read_buff, real_read_size);
    //* 3 把json格式数据发送到mqtt
    log_info("即将发送的数据:%s", json);
    int ret = app_mqtt_sendMsg(json, strlen(json));
    if (ret == 0)
    {
        log_info("数据发生成功 ");
    }
    return 0;
}

/**
 * 接收路由模块接收消息后 传递给设备模块
 * 1  message 转换成字节数组
 * 2  把字节数组写入下行缓冲区
 * 3  安排后续工作给线程池
 */
int app_device_recv_from_mqtt(char *json, int len)
{
    // 1 message 转换成字节数组
    char bytes_buff[100] = {0};
    int bytes_len = app_message_jsonToChars(json, bytes_buff, 100);
    log_info("从mqtt接收到数据: %s", bytes_buff);
    // app_common_charsToHexstr(bytes_buff, bytes_len);

    // 2 把字节数组写入下行缓冲区
    int ret = app_buffer_write(device->down_buffer, bytes_buff, bytes_len);
    if (ret < 0)
    {
        log_error("下行缓冲区写失败");
        return -1;
    }
    // 3 安排后续工作给线程池
    app_pool_registerTask(app_device_write, device);

    return 0;
}

/**
 * 从设备模块的下行缓冲区 写入芯片中 （异步 由线程池执行）
 * 1  把设备结构体中的 下行缓冲区数据提取数据 1 提取帧头 2 提取帧体
 * 2 做写前预处理
 * 3  写入设备文件中 write
 */
int app_device_write(void *arg)
{

    // 1 把设备结构体中的 下行缓冲区数据提取数据 1 提取帧头 2 提取帧体
    char data_buff[100];
    int data_len = app_buffer_read(device->down_buffer, data_buff, 100);
    // 2 做写前预处理
    if (data_len > 0 && device->pre_write)
    {
        data_len = device->pre_write(data_buff, data_len);
    }
    // 3  写入设备文件中 write
    if (data_len > 0)
    {
        log_info("即将向设备文件中写入数据：");
        app_common_charsToHexstr(data_buff, data_len);
        // 控制写入间隔
        log_info("上次写入时间 :%lld", device->last_write_ts_ms);
        if (device->last_write_ts_ms > 0)
        {
            long curts_ms = app_common_getCurrentTime();
            // 当前时间-上次写入时间=实际间隔
            long interval_ms = curts_ms - device->last_write_ts_ms;
            if (interval_ms < device->interval_ms)
            {
                // 要求间隔-实际间隔 = 等待时间
                usleep((device->interval_ms - interval_ms) * 1000);
            }
        }
        ssize_t real_write_size = write(device->fd, data_buff, data_len);

        if (real_write_size < 0)
        {
            perror("写入设备文件失败");
            return -1;
        }
        log_info("写入设备文件成功,写入数据为%s", data_buff);
        log_info("当前时间 %lld", app_common_getCurrentTime());
        device->last_write_ts_ms = app_common_getCurrentTime();
    }
    return 0;
}

/**
 * 销毁设备结构体
 */
void app_device_destroy()
{
    pthread_cancel(device->read_thread);
    close(device->fd);
    app_buffer_free(device->up_buffer);
    app_buffer_free(device->down_buffer);
    free(device->dev_filename);
    free(device);
}
